import {Module} from "../framework.js"
import FuseJS from "../../3rd/fuse/fuse.basic.esm.min.js";
import DataStorage from "../data-storage.js"
import D from "../delegator.js"
import * as SearchEvent from './search-event.js'
import * as UI from "../ui.js"
import * as SidebarEvent from "../sidebar/sidebar-event.js"

class SearchData {
    constructor(meta) {
        this.SUID = meta.SUID;
        this.Update(meta);
    }
    Update(meta) {
        this.name = meta.name;
        this.createTime = meta.createTime.toString();
        this.modifyTime = meta.modifyTime.toString();
        this.brief = meta.brief;
        this.tags = meta.tags;
    }
}

function _GetRenderedHTMLText(data) {
    return `<a href="javascript:;" id='${data.item.SUID}' class="list-group-item list-group-item-action" aria-current="true">
    <div class="d-flex w-100 justify-content-between">
        <h5 class="mb-1">${data.item.name}</h5>
        <small>3 days ago</small>
    </div>
    <p class="mb-1">${data.item.brief}</p>
    <small>${data.item.tags.join(',')} | ${data.score}</small>
</a>`;
}

export default class Search extends Module {
    constructor(disp) {
        super(disp);

        const options = {
            // isCaseSensitive: false,
            includeScore: true,
            // shouldSort: true,
            includeMatches: true,
            // findAllMatches: false,
            minMatchCharLength: 3,
            // location: 0,
            threshold: 0.6,
            distance: 30,
            // useExtendedSearch: false,
            // ignoreLocation: false,
            // ignoreFieldNorm: false,
            keys: [
                "name",
                "brief",
                //"createTime",
                //"modifyTime",
                //"tags",
            ]
        };
        this._arrSearchData = [];
        this._fuse = new FuseJS(this._arrSearchData, options);


        // logic
        this._ui= UI.UISearch();
        this._ui.closeBtn.onclick = _ => {this._ui.Hide();}; 
        this._ui.element.onclick = e => {
            return;
            let _elem = e.target;
            D(e.target);
            while(D.HasTarget()) {
                if(_elem.classList.contains('list-group-item')) {
                    const _PID = _elem.id;
                    this.Dispatch(SearchEvent.SearchResultSelectedEvent(_PID));
                    return;
                }
                D.SetParentAsTarget();
            }
        };
        this._ui.inputElem.onchange = e => {
            const pattern = D(this._ui.inputElem).GetInputValue();
            const _result = this._fuse.search(pattern);

            this._ui.resultElem.replaceChildren();
            this._ui.BeforeAdd();
            for(let i = 0, N = _result.length; i < N; ++i) {
                const _data = _result[i];
                const _item = _data.item;
                this._ui.AddItem(_item.SUID, _item.name, _item.brief, _item.tags.join(','), _data.score);

            }
            this._ui.EndAdd();
        };


        this.Subscribe(SidebarEvent.EVT_SEARCH_CLICKED, _ => {
            this.Show();
        });
        const _rl = DataStorage.RegistListener;
        _rl(DataStorage.EVT_DATASTORAGE_METAS_FETCHED, (params) => {
            const _metaDataListData = params.pageTree;
            let _node = _metaDataListData.TraverseAll();
            while (_node) {
                this._fuse.add(new SearchData(_node.data));
                _node = _metaDataListData.TraverseAll(_node);
            }
        })
        _rl(DataStorage.EVT_DATASTORAGE_META_ADDED, (params) => {
            /// `meta` is instance of MetaData from common.js
            this._fuse.add(new SearchData(params.pageProperty));
        })
        _rl(DataStorage.EVT_DATASTORAGE_META_MODIFIED, (params) => {
            const _metaData = params.pageProperty;
            let _sd = this._arrSearchData.find(value => value.SUID === _metaData.SUID);
            if (_sd) {
                _sd.Update(_metaData);
            }
        })
        _rl(DataStorage.EVT_DATASTORAGE_META_DELETED, (params) => {
            this._fuse.remove(value => value.SUID === params.PID);
        })
    }

    Show() {
        this._ui.Show();
    }

    Hide(immediate = false) {
        this._ui.Hide();
    }
}

